package tech.realcpf.duckengine1.duckdb;

import org.duckdb.DuckDBResultSet;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class MapProcessor implements ResultProcessor {
    @Override
    public Object process(ResultSet rs, boolean close) throws SQLException {
        List<Map<String, Object>> data = new LinkedList<>();
        int count = rs.getMetaData().getColumnCount();
        ResultSetMetaData resultSetMetaData = rs.getMetaData();
        Map<String, Object> header = new HashMap<>(count);
        String[] classTypes = new String[count + 1];
        String[] headerName = new String[count + 1];
        for (int i = 1; i <= count; i++) {
            header.put(resultSetMetaData.getColumnName(i), resultSetMetaData.getColumnClassName(i));
            classTypes[i] = resultSetMetaData.getColumnClassName(i);
            headerName[i] = resultSetMetaData.getColumnName(i);
        }
        data.add(header);
        while (rs.next()) {
            Map<String, Object> row = new HashMap<>(count);
            DuckDBResultSet duckDBResultSet = (DuckDBResultSet) rs;
            for (int i = 1; i <= count; i++) {
                switch (classTypes[i]) {
                    case "java.lang.Boolean" -> {
                        row.put(headerName[i], duckDBResultSet.getBoolean(i));
                    }
                    case "java.lang.Byte" -> {
                        row.put(headerName[i], rs.getByte(i));
                    }
                    case "java.lang.Short" -> {
                        row.put(headerName[i], rs.getShort(i));
                    }
                    case "java.lang.Integer" -> {
                        row.put(headerName[i], rs.getInt(i));
                    }
                    case "java.lang.Long", "java.lang.BigInteger" -> {
                        row.put(headerName[i], rs.getLong(i));
                    }
                    case "org.duckdb.DuckDBArray" -> {
                        row.put(headerName[i], rs.getArray(i));
                    }
                    case "java.lang.Float" -> {
                        row.put(headerName[i], rs.getFloat(i));
                    }
                    case "java.lang.Double" -> {
                        row.put(headerName[i], rs.getDouble(i));
                    }
                    case "java.lang.BigDecimal" -> {
                        row.put(headerName[i], rs.getBigDecimal(i));
                    }
                    case "java.lang.String" -> {
                        row.put(headerName[i], rs.getString(i));
                    }
                    case "java.time.LocalTime" -> {
                        row.put(headerName[i], rs.getTime(i).toLocalTime());
                    }
                    case "java.time.LocalDate" -> {
                        row.put(headerName[i], rs.getDate(i).toLocalDate());
                    }
                    case "java.sql.Timestamp", "java.time.OffsetDateTime", "java.time.OffsetTime" -> {
                        row.put(headerName[i], rs.getTimestamp(i).toLocalDateTime());
                    }
                    case "org.duckdb.JsonNode" -> {
                        row.put(headerName[i], ((DuckDBResultSet) rs).getJsonObject(i));
                    }
                    case "java.util.UUID" -> {
                        row.put(headerName[i], ((DuckDBResultSet) rs).getUuid(i));
                    }
                    default -> {
                        row.put(headerName[i], rs.getObject(i));
                    }

                }
            }
            data.add(row);
        }
        return data;
    }
}
